home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / ov143b.zip / PATHNAME.C < prev    next >
C/C++ Source or Header  |  1993-01-04  |  14KB  |  362 lines

  1. /*  004  20-Apr-87  pathname.c
  2.  
  3.         Copyright (c) 1987 by Blue Sky Software.  All rights reserved.
  4. */
  5.  
  6. #include "strmem.h"
  7. #include "dosfile.h"
  8.  
  9. #ifndef NULL
  10. #define NULL (0)
  11. #endif
  12.  
  13. #ifndef MAX_PATHLEN
  14. #define MAX_PATHLEN (64)               /* max pathname len under MS/PC-DOS */
  15. #endif
  16.  
  17. #define NAME_LEN (8)                   /* max length of primary file name */
  18. #define EXT_LEN  (3)                   /* max length of extension name    */
  19.  
  20. #ifdef LINT_ARGS
  21. #include <string.h>
  22. void trunc_fn(char *);
  23. void fixdirspec(char *);
  24. char *qualdir(char *, char *);
  25. #else
  26. char *qualdir();
  27. void trunc_fn(), fixdirspec();
  28. char *strupr(), *strrchr(), *strchr(), *strchr(), *strcpy();
  29. #endif
  30.  
  31. struct search_block *nxtfile();
  32.  
  33.  
  34. /****************************************************************************
  35.                           P A R S E P A T H
  36.  ****************************************************************************/
  37.  
  38. char *
  39. parsepath(refdir,reffn,target,isdir,todirp,tofnp)
  40. char *refdir, *reffn, *target, **todirp, **tofnp;
  41. int isdir;
  42. {
  43.    /* I don't know if this should really be called parsepath, but I couldn't
  44.       think of a better name.  Here's what it does: given a reference
  45.       directory specification, a reference file name, and a traget name
  46.       (dir and/or file name) it creates a fully qualified target name
  47.       consisting of a drive specification and file name.  One of the fancier
  48.       things this routine does (or has done) is expand relative dir spec's
  49.       (e.g. ..\ov) to fully qualified dir spec's (e.g. c:\src\ov).  This
  50.       requires that the reference dir be fully qualified.  parsepath()
  51.       will also return individual dir and/or file name strings if pointers
  52.       to char pointers are passed as todirp and tofnp.  If one or both of
  53.       these strings are not desired, pass the value NULL instead of a
  54.       pointer address.  All three of the parsepath() result strings are
  55.       in dynamically allocated memory that can be free'd with the free()
  56.       function.
  57.  
  58.       Oh yea, the isdir parameter tells parsepath() if the target name
  59.       is just a dir name (isdir = true) or if it contains a file name
  60.       (and maybe a dir name) (isdir = false).  This parameter was added
  61.       for performance - parsepath() doesn't need to call isadir() each
  62.       time if the caller already knows its not just a dir name.
  63.  
  64.       Note: the refdir is used as if it were the current dir when qualifying
  65.       the target name.  If the target contains no dir spec, the refdir spec
  66.       will be used.  If the target contains a relative dir spec, the refdir
  67.       will be used as the starting point (a relative dir spec is relative to
  68.       the refdir).
  69.  
  70.       BUT if the target contains a drive code that is different than the
  71.       drive code in refdir, parsepath() will call the external function
  72.       getcdir() to get the current dir spec for the target drive and use
  73.       that as the refdir instead of the passed refdir.
  74. */
  75.  
  76.    char *tmp = NULL;
  77.    char *tardir, *tarfn, *np;
  78.  
  79.    /* make sure both the reference dir and the target use \ instead of / */
  80.  
  81.    fixdirspec(refdir);  strupr(refdir);        /* uppercase to make */
  82.    fixdirspec(target);  strupr(target);        /* compares easier   */
  83.  
  84.    /* determine if the target is on the same drive as the reference,
  85.       get a new reference dir if not */
  86.  
  87.    if (strlen(target) > 1 && target[1] == ':')        /* target have a drive? */
  88.       if (*refdir != *target) {                       /* different than ref?  */
  89.          refdir = tmp = (char *) Malloc(MAX_PATHLEN+4);    /* make new refdir */
  90.          strncpy(tmp,target,2);
  91.          tmp[2] = '\\';
  92.          getcdir(*target-'A'+1,tmp+3);       /* sorta like getcwd() for drive */
  93.       }
  94.  
  95.    /* determine if the target string has a directory and/or file name */
  96.  
  97.    if (isdir) {                /* is it only a dir (no file name)? */
  98.  
  99.       tardir = Strdup(target);
  100.       tarfn  = Strdup(reffn);
  101.  
  102.    } else              /* well is it a dir and file name? */
  103.  
  104.       if ((np = strrchr(target,'\\')) || (np = strrchr(target,':'))) {
  105.          tardir = Strndup(target,np-target+1);
  106.          tarfn  = Strdup(np+1);
  107.  
  108.       } else {         /* must be just a file name */
  109.  
  110.          tardir = NULL;
  111.          tarfn  = Strdup(target);
  112.       }
  113.  
  114.    trunc_fn(tarfn);    /* make sure fn is no bigger than expected */
  115.  
  116.    /* if a target dir was supplied, make sure its fully qualified */
  117.  
  118.    if (tardir) {
  119.       np = tardir;
  120.       tardir = qualdir(refdir,tardir);
  121.       free(np);
  122.    } else
  123.       tardir = Strdup(refdir);
  124.  
  125.    if (tmp)                    /* free locally allocated refdir string */
  126.       free(tmp);
  127.  
  128.    /* make a copy of the fully qualified name for the user */
  129.  
  130.    target = (char *) Malloc(strlen(tardir)+strlen(tarfn)+2);
  131.    strcpy(target,tardir);
  132.    if (target[strlen(target)-1] != '\\')
  133.       strcat(target,"\\");
  134.    strcat(target,tarfn);
  135.  
  136.    /* return the seperate target dir/fn strings to user or release'm */
  137.  
  138.    if (todirp)
  139.       *todirp = tardir;
  140.    else
  141.       free(tardir);
  142.  
  143.    if (tofnp)
  144.       *tofnp = tarfn;
  145.    else
  146.       free(tarfn);
  147.  
  148.    return(target);             /* return the full target name */
  149. }
  150.  
  151.  
  152. /****************************************************************************
  153.                               Q U A L D I R
  154.  ****************************************************************************/
  155.  
  156. /* This routine expands a partial dir specification to a fully qualified
  157.    dir pathname.  It requires a fully qualified refernece dir name and the
  158.    partial dir pathname.  The reference dir spec is expected to start with
  159.    a drive code and end without a trailing '\'.  The partial dir spec may
  160.    or may not contain a drive code, the qualified result will.  If an error
  161.    is encountered, this routine returns a null string. */
  162.  
  163. char *
  164. qualdir(refdir,partdir)        /* fully qualify a partial dir spec */
  165. char *refdir, *partdir;
  166. {
  167.    register char *cp, *path;
  168.    char *psave, *sp, fullpath[MAX_PATHLEN+4];
  169.  
  170.    /* setup the drive code of the resultant dir spec */
  171.  
  172.    strncpy(fullpath,refdir,3);         /* copy over "<drive>:\" */
  173.    fullpath[3] = '\0';
  174.  
  175.    refdir += 3;                        /* don't need ref drive\root again */
  176.    if (strlen(partdir) > 1 && partdir[1] == ':')   /* and don't really */
  177.       partdir += 2;                                /* need partial drive */
  178.  
  179.    /* initialize the full pathname to the reference dir name if the partial
  180.       name doesn't start at the root */
  181.  
  182.    if (*partdir == '\\')               /* partial (relative) start at root? */
  183.       partdir++;                       /* already got \ above, don't need now */
  184.  
  185.    else {                              /* must really be partial spec */
  186.  
  187.       strcat(fullpath,refdir);                 /* start from reference dir */
  188.       if (fullpath[strlen(fullpath)-1] != '\\')    /* we want trailing \ */
  189.          strcat(fullpath,"\\");                    /*   for now */
  190.    }
  191.  
  192.    cp = fullpath + strlen(fullpath);   /* always points to end of fullpath */
  193.  
  194.    path = psave = Strdup(partdir);     /* need a copy we can modify */
  195.  
  196.    /* process the partial pathname a dir at a time - still more to do
  197.       while path has something in it */
  198.  
  199.    while(strlen(path)) {
  200.  
  201.       if (sp = strchr(path,'\\'))      /* find end of current dir name */
  202.          *sp = '\0';                   /* null terminate it */
  203.  
  204.       if (strcmp(path,".") == 0)       /* "." entry is current dir */
  205.          ;                             /*   so there is nowhere to go */
  206.  
  207.       else
  208.  
  209.          if (strcmp(path,"..") == 0) {         /* ".." means goto parent dir */
  210.             *--cp = '\0';                      /* zap trailing \ */
  211.             if (cp = strrchr(fullpath,'\\'))   /* find \ before current */
  212.                *++cp = '\0';                   /* zap curr - parent now last */
  213.             else {                             /* error, no more parents! */
  214.                *fullpath = '\0';               /* return null string */
  215.                break;                          /* stop processing */
  216.             }
  217.  
  218.          } else                /* not "." or "..", must be subdir name */
  219.  
  220.             if (strlen(fullpath) + strlen(path) < sizeof(fullpath)) { /* fit? */
  221.                strcpy(cp,path);
  222.                strcat(cp,"\\");                /* add subdir to fullpath */
  223.                cp += strlen(cp);               /* add trailing \, new end */
  224.             } else {                           /* error! pathname too big */
  225.                *fullpath = '\0';
  226.                break;
  227.             }
  228.  
  229.       if (sp)                  /* if there was a \, skip beyond to chk */
  230.          path = sp + 1;        /*   for another one, otherwise there can't */
  231.       else                     /*   be anything else to process */
  232.          break;
  233.    }
  234.  
  235.    free(psave);                                /* free local copy */
  236.  
  237.    if (strlen(fullpath) > 3)                   /* remove trailing \ if */
  238.       fullpath[strlen(fullpath)-1] = '\0';     /*   not at root */
  239.  
  240.    return(Strdup(fullpath));                   /* give caller his own copy */
  241. }
  242.  
  243.  
  244. /******************************************************************************
  245.                            F I X D I R S P E C
  246.  ******************************************************************************/
  247.  
  248. void
  249. fixdirspec(dir)        /* convert /'s to \'s in dir specifications */
  250. register char *dir;
  251. {
  252.    while (dir = strchr(dir,'/'))       /* make sure all /'s turned to \'s */
  253.       *dir++ = '\\';
  254. }
  255.  
  256.  
  257. /******************************************************************************
  258.                             T R U N C _ F N
  259.  ******************************************************************************/
  260.  
  261. void
  262. trunc_fn(fn)   /* truncate (too) long filenames the way DOS would */
  263. register char *fn;
  264. {
  265.    register char *ext;
  266.  
  267.    if ((ext = strchr(fn,'.')) == NULL) /* make ext point just past the */
  268.       ext = fn + strlen(fn);           /*   end of the primary name    */
  269.  
  270.    if (ext - fn > NAME_LEN)            /* truncate the primary name if */
  271.       ext = strcpy(fn+NAME_LEN,ext);   /*   its too long               */
  272.  
  273.    if (strlen(ext) > EXT_LEN + 1)      /* truncate the extension if    */
  274.       *(ext + EXT_LEN + 1) = '\0';     /*   its too long (+1 for '.')  */
  275. }
  276.  
  277.  
  278. /******************************************************************************
  279.                                I S A D I R
  280.  *****************************************************************************/
  281.  
  282. isadir(refdir,dir)     /* returns 1 if dir represents a directory name, */
  283. char *refdir, *dir;    /*   0 if not. */
  284. {
  285.    int firsttime;
  286.    register int s;
  287.    char *qdir, *tmp = NULL;
  288.    register struct search_block *sbp;
  289.  
  290.     /* For MSDOS, we assume the path is a directory name if it ends in \, /,
  291.        its just a drive specifier (A:), is "." or "..", or DOS says its a
  292.        directory */
  293.  
  294.    /* check the easy cases first */
  295.  
  296.    fixdirspec(dir);            /* make all /'s into \'s */
  297.  
  298.    if ((s = dir[strlen(dir)-1]) == '\\' || s == ':' || strcmp(dir,".") == 0 ||
  299.        strcmp(dir,"..") == 0)
  300.       return(1);
  301.  
  302.    /* need to ask DOS if this is a directory */
  303.  
  304.    /* determine if the target is on the same drive as the reference,
  305.       get a new reference dir if not - this is done here so it doesn't
  306.       need to be done by isadir() callers - note parsepath() does pretty
  307.       much the same thing, maybe this should be in qualdir() */
  308.  
  309.    if (strlen(dir) > 1 && dir[1] == ':')       /* target have a drive? */
  310.       if (*refdir != *dir) {                   /* different than ref?  */
  311.          refdir = tmp = (char *) Malloc(MAX_PATHLEN+4);    /* make new refdir */
  312.          strncpy(tmp,dir,2);
  313.          tmp[2] = '\\';
  314.          getcdir(*dir-'A'+1,tmp+3);          /* sorta like getcwd() for drive */
  315.       }
  316.  
  317.    qdir = qualdir(refdir,dir);         /* qualify it first */
  318.  
  319.    firsttime = 1;
  320.    s = ((sbp = nxtfile(qdir,0x10,&firsttime)) && sbp->attrib & 0x10);
  321.  
  322.    free(qdir);
  323.    if (tmp)
  324.       free(tmp);
  325.  
  326.    return(s);
  327. }
  328.  
  329.  
  330. /******************************************************************************
  331.  **                       C H A N G E _ D I R                                **
  332.  *****************************************************************************/
  333.  
  334. change_dir(dir)        /* change the current directory */
  335. register char *dir;
  336. {
  337.    int newdir, cur_drive, rc;
  338.  
  339.    rc = 0;                             /* assume all will go okay */
  340.  
  341.    if (strlen(dir) > 1 && dir[1] == ':') {     /* isolate any drive letter */
  342.       cur_drive = current_drive();             /* current drive (A,B,...) */
  343.       newdir = toupper(*dir);                  /* wanted new dir */
  344.       change_drive(newdir);                    /* switch to named drive */
  345.       if (current_drive() != newdir)           /* did we get there? */
  346.          return(-1);                           /*   no!, give up now */
  347.       dir += 2;                                /*   yes, skip over drive: */
  348.    } else
  349.       cur_drive = 0;                           /* means no drive switch */
  350.  
  351.    if (strlen(dir) > 0)                        /* is there a dir spec? */
  352.       if (chdir(dir) != 0) {                   /* switch directories */
  353.          if (cur_drive)                        /* drive switched? */
  354.             change_drive(cur_drive);           /*   error, switch back */
  355.          rc = -1;                              /* return non 0 error code */
  356.       }
  357.  
  358.    return(rc);                 /* tell caller if we worked */
  359. }
  360.  
  361.  
  362.